<template>
  <div class="model-box">
    <div class="button-box">
      <div style="display: flex;">
        <ac-input v-model="filterName" style="width: 150px" placeholder="知识库名称" />
        <el-button style="margin-left: 10px;" type="primary" @click="loadData">
          <cc-icon iconId="018dc9c3efe489a7d117" style="margin-right: 5px" />查询
        </el-button>
        <div @click="selectMode = !selectMode" style="margin-left: 20px;cursor: pointer">
          <el-checkbox v-model="selectMode" />
          <span style="margin-left: 5px">选择模式</span>
        </div>
        <el-button v-if="selectMode" style="margin-left: 10px;" type="primary" @click="selectAll">
          <cc-icon iconId="018dca412c4e207388f7" style="margin-right: 5px" />全选
        </el-button>
        <el-button v-if="selectMode" style="margin-left: 10px;" type="primary" @click="unselectAll">
          <cc-icon iconId="018dca412c4ebd53fd1d" style="margin-right: 5px" />取消选择
        </el-button>
      </div>
      <div class="button-item">
        <el-upload
          action=""
          :http-request="handleImport"
          :show-file-list="false"
          accept=".dat"
        >
          <el-button
            style="
              color: #ffffff;
              background-color: #00CED1;
              border: 1px solid #00CED1;
            "
          >
            <ac-icon
              iconId="018dcc257a83b0d6deab"
              title="导入知识库"
              style="margin-right: 8px"
            />导入知识库
          </el-button>
        </el-upload>

        <el-button
          style="
            color: #ffffff;
            background-color: #FF8C00;
            border: 1px solid #FF8C00
          "
          @click="download()"
        >
          <ac-icon
            iconId="018dcc257a840e260284"
            title="导出知识库"
            style="margin-right: 8px"
          />导出知识库
        </el-button>
      </div>
    </div>

    <div class="item-box" @click="addItem">
      <div style="font-size: 14px; display: flex;align-items: center">
        <ac-icon
          iconId="018dca3b4707c4c43a2f"
          size="18"
          color="#474747"
        />
        <span style="margin-left: 10px">添加知识库</span>
      </div>
    </div>

    <div
      v-for="item in dataList"
      :key="item.id"
      :class="['item-box', selectMode && item.checked ? 'active' : '']"
      @click="clickItem(item)"
    >
      <div class="item-main">
        <div class="item-header">
          <div class="item-name-line">
            <span class="item-name" :title="item.name">{{item.name}}</span>
          </div>
        </div>
        <div class="item-type">
          <div>
            <span>向量模型</span>
            <span class="text">{{item.modelName}}</span>
          </div>
          <div>
            <span>检索方式</span>
            <span class="text">
              <ac-show-dict :dictValue="item.searchMode" dictCode="dictAiSearchMode" />
            </span>
          </div>
        </div>
        <div class="item-remark">
          <span :title="item.remark">{{item.remark || '暂无备注'}}</span>
        </div>
        <div class="item-button">
          <div class="time-box"></div>
          <div class="button-list">
            <el-tooltip
              effect="light"
              content="文档管理"
              popper-class="padding-10-15"
            >
              <ac-icon
                size="15"
                iconId="018ece4f74045acb7f43"
                color="#00CED1"
                @click.stop="showFile(item)"
              />
            </el-tooltip>
            <el-tooltip
              effect="light"
              content="编辑"
              popper-class="padding-10-15"
            >
              <ac-icon
                size="15"
                iconId="018dca6db20c6a3aaf68"
                color="#0085f6"
                @click.stop="editItem(item)"
              />
            </el-tooltip>
            <el-tooltip
              effect="light"
              content="删除"
              popper-class="padding-10-15"
            >
              <ac-icon
                size="15"
                iconId="018dc9c3efd3a0502886"
                color="#F56C6C"
                @click.stop="deleteItem(item)"
              />
            </el-tooltip>
          </div>
        </div>
      </div>
    </div>
  </div>

  <el-dialog
    v-model="visible"
    :title="title"
    width="700px"
    :close-on-click-modal="false"
    destroy-on-close
    draggable
  >
    <el-form
      ref="dataForm"
      label-width="120px"
      label-position="right"
      :model="formData"
      :rules="rules"
    >
      <el-row>
        <el-col :span="24">
          <el-form-item label="知识库名称" prop="name">
            <el-input v-model="formData.name"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="12">
          <el-form-item label="文件分块大小" prop="chunkSize">
            <ac-number v-model="formData.chunkSize" />
          </el-form-item>
        </el-col>
        <!--
        <el-col :span="12">
          <el-form-item label="分块重复字符数" prop="chunkOverlap">
            <ac-number v-model="formData.chunkOverlap" />
          </el-form-item>
        </el-col>
        -->
        <el-col :span="12">
          <el-form-item label="分块最少字数" prop="chunkMinSize">
            <ac-number v-model="formData.chunkMinSize" />
          </el-form-item>
        </el-col>
        <!--
        <el-col :span="12">
          <el-form-item label="分块分割符" prop="chunkSeparator">
            <template #label>
              <span>分块分割符</span>
              <el-tooltip content="多个分割符，以英文逗号“,”分割。">
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <ac-input v-model="formData.chunkSeparator" />
          </el-form-item>
        </el-col>
        -->
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="向量化模型" prop="modelId">
            <ac-remote-select
              v-model="formData.modelId"
              data-url="/system/aiModel/queryPage"
              :option="{id: formData.modelId, name: formData.modelName}"
              :query="{supplierModelType: '02'}"
            />
          </el-form-item>
        </el-col>
      </el-row>
      <!--
      <el-row>
        <el-col :span="24">
          <el-form-item label="检索方式" prop="searchMode">
            <ac-dict-radio
              v-model="formData.searchMode"
              dictCode="dictAiSearchMode"
            />
          </el-form-item>
        </el-col>
      </el-row>
      -->
      <el-row v-if="formData.searchMode === '03'">
        <el-col :span="24">
          <el-form-item label="重排序方式" prop="rerankMode">
            <ac-dict-radio
              v-model="formData.rerankMode"
              dictCode="dictAiRerankMode"
            />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row
        v-if="formData.searchMode === '03' && formData.rerankMode === '01'"
      >
        <el-col :span="12">
          <el-form-item label="语义权重" prop="semanticWeight">
            <template #label>
              <span>语义权重</span>
              <el-tooltip content="通过调整分配的权重，重新排序策略确定是优先进行语义匹配还是关键字匹配">
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <ac-number v-model="formData.semanticWeight" :min="0" :max="1" point="1" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="关键字权重">
            <ac-number v-model="formData.primaryKeyWeight" :min="0" :max="1" point="1" />
          </el-form-item>
        </el-col>
      </el-row>
      <!--
      <el-row
        v-if="formData.searchMode === '01'
          || formData.searchMode === '02'
          || (formData.searchMode === '03' && formData.rerankMode === '02')"
      >
        <el-col :span="24">
          <el-form-item label="重排序模型" prop="rerankModelId">
            <template #label>
              <span>重排序模型</span>
              <el-tooltip content="重排序模型将根据候选文档列表与用户问题语义匹配度进行重新排序，从而改进语义排序的结果">
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <ac-remote-select
              v-model="formData.rerankModelId"
              data-url="/system/aiModel/queryPage"
              :option="{id: formData.rerankModelId, name: formData.rerankModelName}"
              :query="{supplierModelType: '10'}"
            />
          </el-form-item>
        </el-col>
      </el-row>
      -->
      <el-row>
        <el-col :span="12">
          <el-form-item label="获取最优数量" prop="topSize">
            <template #label>
              <span>获取最优数量</span>
              <el-tooltip content="用于筛选与用户问题相似度最高的文本片段，系统同时会根据选用下文窗口大小动态调整分段数量">
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <ac-number v-model="formData.topSize" :min="1" :max="10" />
          </el-form-item>
        </el-col>
        <el-col
          :span="12"
          v-if="formData.searchMode === '01'
            || (formData.searchMode === '02' && formData.rerankModelId)
            || formData.searchMode === '03'"
        >
          <el-form-item label="相似度阈值">
            <template #label>
              <span>相似度阈值</span>
              <el-tooltip content="用于设置文本片段筛选的相似度阈值">
                <ac-icon iconId="018dca8ec9890493be26" />
              </el-tooltip>
            </template>
            <div class="inline-box">
              <ac-dict-switch v-model="formData.useSimilarityThreshold" dictCode="dictYesNo" />
              <ac-number
                v-if="formData.useSimilarityThreshold === '1'"
                v-model="formData.similarityThreshold"
                style="width: 127px;margin-left: 8px;"
                :point="2"
                :min="0"
                :max="1"
              />
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="24">
          <el-form-item label="备注" prop="remark">
            <el-input v-model="formData.remark" type="textarea" :rows="5"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="visible=false"
      >取消</el-button>
      <el-button
        type="primary"
        size="default"
        :loading="loading"
        @click="submit"
      >提交</el-button>
    </template>
  </el-dialog>

  <el-dialog
    v-model="fileVisible"
    title="知识库详情"
    :close-on-click-modal="false"
    destroy-on-close
    fullscreen
    style="background-color: #f5f5f5"
  >
    <div class="dialog-body">
      <div class="left">
        <div
          :class="showName === 'document' ? 'active' : ''"
          @click="showName = 'document'"
        >文档详情</div>
        <div
          :class="showName === 'hitTest' ? 'active' : ''"
          @click="showName = 'hitTest'"
        >命中测试</div>
      </div>
      <div
        v-show="showName === 'document'"
        class="document-body"
      >
        <div class="file-header">
          <ac-input v-model="fileName" style="width: 150px" placeholder="文档名称" />
          <el-button style="margin-left: 10px;" type="primary" @click="loadFileData">
            <cc-icon iconId="018dc9c3efe489a7d117" style="margin-right: 5px" />查询
          </el-button>
          <el-upload
            style="margin-left: 10px;"
            action=""
            multiple
            :before-upload="handleBeforeUpload"
            :http-request="handleUpload"
            :file-list="fileList"
            :show-file-list=false
            accept=".docx,.doc,.pdf,.txt"
          >
            <el-button type="success">
              <ac-icon iconId="018dc9c3efd2131ecc10" />
              <span style="margin-left: 5px;">文档上传</span>
            </el-button>
          </el-upload>
          <el-button style="margin-left: 10px;" type="success" @click="selectEmbedding">
            <cc-icon iconId="018ece4f77127fe06699" style="margin-right: 5px" />向量化
          </el-button>
          <el-button style="margin-left: 10px;" type="primary" @click="selectFileAll">
            <cc-icon iconId="018dca412c4e207388f7" style="margin-right: 5px" />全选
          </el-button>
          <el-button style="margin-left: 10px;" type="primary" @click="unselectFileAll">
            <cc-icon iconId="018dca412c4ebd53fd1d" style="margin-right: 5px" />取消选择
          </el-button>
        </div>
        <div
          v-for="(file, index) in fileList"
          :key="index"
          class="file-item"
          :class="['file-item', selectMode && file.checked ? 'active' : '']"
          @click="file.checked = !file.checked"
        >
          <div class="file-box">
            <div class="file-name">
              <span>{{file.name}}</span>
            </div>
            <div class="file-box-footer">
            <span
              v-if="file.process === 1"
              class="file-status"
            >
              <ac-icon
                size="15"
                color="#999"
                iconId="018dcab3d3dfd6e82393"
                class="spinner"
                style="margin-right: 5px"
              />上传中...
            </span>
              <span
                v-else-if="file.process === 2"
                class="file-status"
              >已上传</span>
              <span
                v-else-if="file.process === 3"
                class="file-status"
              >
              <ac-icon
                size="15"
                color="#999"
                iconId="018dc9c3f0017f08ea18"
                style="margin-right: 5px"
              />等待向量化
            </span>
              <span
                v-else-if="file.process === 4"
                class="file-status"
              >
              <ac-icon
                size="15"
                color="#999"
                iconId="018dcab3d3dfd6e82393"
                class="spinner"
                style="margin-right: 5px"
              />正在向量化...
            </span>
              <span
                v-else-if="file.status === '0'"
                style="color: #F56C6C"
                class="file-status"
              >
              <ac-icon
                size="15"
                iconId="018dca412c4ebd53fd1d"
                style="margin-right: 5px"
              />未向量化
            </span>
              <span
                v-else-if="file.status === '1'"
                style="color: #67C23A"
                class="file-status"
              >
              <ac-icon
                size="15"
                iconId="018dca412c4e207388f7"
                style="margin-right: 5px"
              />已向量化
            </span>
              <span v-else class="file-status"></span>
              <div class="button-list">
                <el-tooltip
                  effect="light"
                  content="向量化"
                  popper-class="padding-10-15"
                >
                  <ac-icon
                    size="15"
                    iconId="018ece4f77127fe06699"
                    color="#0085f6"
                    @click.stop="checkEmbeddingFile(file)"
                  />
                </el-tooltip>
                <el-tooltip
                  effect="light"
                  content="下载"
                  popper-class="padding-10-15"
                >
                  <ac-icon
                    size="15"
                    iconId="018dc9c3efed1f464d38"
                    color="#0085f6"
                    @click.stop="downloadFile(file)"
                  />
                </el-tooltip>
                <el-tooltip
                  effect="light"
                  content="删除"
                  popper-class="padding-10-15"
                >
                  <ac-icon
                    size="15"
                    iconId="018dc9c3efd3a0502886"
                    color="#F56C6C"
                    @click.stop="deleteFile(file)"
                  />
                </el-tooltip>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div
        v-show="showName === 'hitTest'"
        class="hit-test-body"
      >
        <div>
          <span style="font-weight: bolder;font-size: 18px;margin-right: 8px">命中测试</span>
          <span>测试用户提问匹配情况，确保回答效果。</span>
        </div>
        <div class="chat-line" ref="chatRef">
          <div
            v-for="(chat, index) in chatList"
            :key="index"
            class="chat-item"
          >
            <div class="question" style="font-size: 18px;font-weight: bolder">
              检索：{{chat.question}}
            </div>
            <div class="answer">
              <span>结果：</span>
              <span :class="chat.failure ? 'failure' : ''">
                {{chat.answer}}
              </span>
            </div>
          </div>
        </div>
        <div class="param-line">
          <span style="margin-right: 20px">参数配置</span>
          <span>条数：</span>
          <span><ac-number v-model="hitTestData.topSize" style="width: 100px;" /></span>
          <span style="margin-left: 20px;">相似度阈值：</span>
          <span>
            <ac-number
              v-model="hitTestData.similarityThreshold"
              style="width: 100px;"
              point="2"
              :min="0"
              :max="1"
            />
          </span>
        </div>
        <div class="query-line">
          <el-input
            v-model="hitTestData.query"
            placeholder="请输入"
            :disabled="chatLoading"
            @keyup.enter="sendMessage"
          >
            <template #suffix>
              <ac-icon
                v-if="!chatLoading"
                style="cursor: pointer;"
                iconId="018ece4f6c1823ddf065" 
                @click="sendMessage" 
              />
              <ac-icon
                v-else
                style="cursor: pointer;"
                iconId="018ece4f6e873209b311"
                @click="sendMessage"
              />
            </template>
          </el-input>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';
import api from "@/http/api";
import { ElMessage, ElMessageBox } from "element-plus";
import tool from "@/utils/tool";

const selectMode = ref(false);
const showName = ref('document');
const filterName = ref('');
const dataList = ref([]);
const visible = ref(false);
const title = ref('');
const dataForm = ref();
const formData = ref({});
const loading = ref(false);
const rules = ref({
  name: [
    {required: true, message: '知识库名称不能为空！', trigger: 'blur'},
    {max: 100, message: '知识库名称长度最多只能是100个字符', trigger: ['blur', 'change']}
  ],
  chunkSize: [
    {required: true, message: '文件分块大小不能为空！', trigger: 'blur'}
  ],
  chunkOverlap: [
    {required: true, message: '分块重复字符数不能为空！', trigger: 'blur'}
  ],
  chunkMinSize: [
    {required: true, message: '分块最少字符数不能为空！', trigger: 'blur'}
  ],
  chunkSeparator: [
    {required: true, message: '分块分割符不能为空！', trigger: 'blur'},
    {max: 100, message: '分块分割符长度最多只能是100个字符', trigger: ['blur', 'change']}
  ],
  modelId: [
    {required: true, message: '向量化模型不能为空！', trigger: 'blur'},
  ],
  searchMode: [
    {required: true, message: '检索方式不能为空！', trigger: 'blur'},
  ],
  topSize: [
    {required: true, message: '获取最优数量不能为空！', trigger: 'blur'},
  ],
  rerankMode: [
    {required: true, message: '重排序方式不能为空！', trigger: 'blur'},
  ],
  semanticWeight: [
    {required: true, message: '语义权重不能为空！', trigger: 'blur'},
  ],
  remark: [
    {max: 1000, message: '备注长度最多只能是1000个字符', trigger: ['blur', 'change']}
  ]
});
const fileVisible = ref(false);
const knowledge = ref({});
const fileName = ref('');
const fileList = ref([]);

const chatRef = ref();
const hitTestData = ref({});
const chatList = ref([]);
const chatLoading = ref(false);

const addItem = () => {
  formData.value = {
    chunkSize: 1024,
    // chunkOverlap: 50,
    chunkMinSize: 10,
    // chunkSeparator: '\\n\\n,\\n,。,？,！,.,?,!',
    searchMode: '01',
    topSize: 3,
    // semanticWeight: 0.7,
    // primaryKeyWeight: 0.3,
  };
  title.value = "新增知识库";
  loading.value = false;
  visible.value = true;
};

const clickItem = item => {
  if (selectMode.value) {
    item.checked = !item.checked;
  } else {
    showFile(item);
  }
};

const editItem = async(item) => {
  if (!item) return;
  formData.value = tool.deepClone(item);
  title.value = "编辑知识库";
  loading.value = false;
  visible.value = true;
};

const submit = () => {
  dataForm.value.validate(valid => {
    if (valid) {
      ElMessageBox.confirm('请确认是否提交？', '提示', {type: 'info'}).then(() => {
        loading.value = true;
        api.post('/system/knowledge/save', formData.value).then(res => {
          if(res.code === '1') {
            visible.value = false;
            ElMessage.success(res.message);
            loadData();
          } else {
            ElMessage.error(res.message);
          }
          loading.value = false;
        }).catch(() => {
          loading.value = false;
        });
      });
    } else {
      ElMessage.error('数据录入不正确，请重新检查！');
    }
  });
};

const download = () => {
  const ids = dataList.value.filter(item => item.checked).map(item => item.id);
  if (!ids || ids.length === 0) {
    ElMessage.error("请先选择要导出的知识库！");
    return;
  }

  api.downloadFile('/system/knowledge/exportData', {ids: ids}).then(res => api.saveFileLocal(res));
};

const deleteItem = (supplierModel) => {
  ElMessageBox.confirm('请确认是否删除知识库【' + supplierModel.name + '】？', '提示', {type: 'warning'}).then(() => {
    api.post('/system/knowledge/delete', supplierModel).then(res => {
      if(res.code === '1') {
        ElMessage.success(res.message);
        loadData();
      } else {
        ElMessage.error(res.message);
      }
    });
  });
};

const handleImport = (file) => {
  api.uploadFile('/system/knowledge/importData', {'file': file.file}).then((res) => {
    ElMessage.success(res.message);
    loadData();
  });
};

const loadData = () => {
  dataList.value = [];
  api.post('/system/knowledge/queryList', {name: filterName.value || ''}).then(res => {
    dataList.value = res.data || [];
  });
};

const selectAll = () => {
  dataList.value.forEach(data => data.checked = true);
};

const unselectAll = () => {
  dataList.value.forEach(data => data.checked = false);
};

const showFile = (item) => {
  if (!item.id) return;
  knowledge.value = item;
  showName.value = 'document';
  fileList.value = [];
  hitTestData.value = {
    id: knowledge.value.id,
    topSize: 5,
    similarityThreshold: 0.2
  };
  chatList.value = [];
  loadFileData();
  fileVisible.value = true;
};

const checkEmbeddingFile = async(file) => {
  ElMessageBox.confirm('请确认是否执行向量化？', '提示', {type: 'warning'}).then(() => {
    embeddingFile(file);
  });
};

const embeddingFile = async(file) => {
  try {
    file.process = 4;
    const res = await api.post('/system/knowledgeFile/embedding', {id: file.id});
    file.status = res.data.status;
    file.process = null;
  } catch (e) {
    file.process = null;
    console.log("执行向量化失败！", e);
  }
};

const selectEmbedding = () => {
  const selectList = fileList.value.filter(data => data.checked);
  if (!selectList || selectList.length === 0) {
    ElMessage.error("请先选择要向量化的文档！");
    return;
  }
  ElMessageBox.confirm('请确认是否执行向量化？', '提示', {type: 'warning'}).then(() => {
    selectList.forEach(data => data.process = 3);
    tool.runTask(selectList, 5, embeddingFile);
  });
};

const deleteFile = (file) => {
  ElMessageBox.confirm('请确认是否删除文档【' + file.name + '】？', '提示', {type: 'warning'}).then(() => {
    api.post('/system/knowledgeFile/delete', {id: file.id}).then(() => {
      loadFileData();
    });
  });
};

const downloadFile = (file) => {
  api.downloadFileLocal(file.fileId);
};

const loadFileData = () => {
  const data = {knowledgeId: knowledge.value.id, name: fileName.value};
  api.post('/system/knowledgeFile/queryList', data).then(res => {
    fileList.value = res.data || [];
  });
};

const selectFileAll = () => {
  fileList.value.forEach(data => data.checked = true);
};

const unselectFileAll = () => {
  fileList.value.forEach(data => data.checked = false);
};

const handleUpload = (options) => {
  return new Promise((resolve, reject) => {
    const data = {knowledgeId: knowledge.value.id, 'file': options.file};
    api.uploadFile('/system/knowledgeFile/upload', data).then((res) => {
      const file = fileList.value.find(item => item.itemFlag === options.file.itemFlag);
      if (file) {
        file.id = res.data.id;
        file.name = res.data.name;
        file.fileId = res.data.fileId;
        file.status = res.data.status;
        file.process = null;
      }
      resolve();
    }).catch(() => {
      const index = fileList.value.findIndex(item => item.itemFlag === options.file.itemFlag);
      fileList.value.splice(index, 1);
      reject();
    });
  });
};

const itemFlag = ref(1);
const handleBeforeUpload = (file) => {
  file.itemFlag = ++itemFlag.value;
  const isLt100M = file.size / 1024 / 1024 < 2;
  if (!isLt100M) {
    ElMessage.error("文档大小不能超过 100MB!");
  } else {
    fileList.value.unshift({itemFlag: file.itemFlag, name: file.name, process: 1});
  }

  return isLt100M;
};

const sendMessage = () => {
  if (!hitTestData.value.query) return;

  chatLoading.value = true;
  const data = {
    id: tool.uuid(),
    failure: false,
    question: hitTestData.value.query,
    answer: '正在思考...'
  };
  chatList.value.unshift(data);
  api.post('/system/knowledge/hitTest', hitTestData.value).then(res => {
    data.failure = !res.data;
    data.answer = res.data || '命中失败';
    hitTestData.value.query = '';
    chatLoading.value = false;
  }).catch(() => {
    chatLoading.value = false;
  });
  nextTick(() => {
    chatRef.value.scrollTop = 0;
  });
};

// watch(() => formData.value.semanticWeight, () => {
//   if (typeof formData.value.semanticWeight === 'undefined') {
//     formData.value.semanticWeight = 0.7;
//   }
//   formData.value.primaryKeyWeight = 1 - formData.value.semanticWeight;
// });

onMounted(() => {
  loadData();
});
</script>

<style scoped lang="scss">
.model-box {
  padding: 20px;
  height: calc(100% - 40px);
  background: #f5f5f5;
  display: grid;
  grid-template-columns: repeat(auto-fill, 250px);
  grid-gap: 15px;
  justify-content: center;
  align-content: flex-start;
  overflow: auto;
  .button-box {
    display: flex;
    width: 100%;
    grid-column: 1 / -1;
    text-align: right;
    .button-item {
      flex-grow: 1;
      display: flex;
      flex-direction: row;
      justify-content: flex-end;
      gap: 15px;
      margin-bottom: 20px;
    }
  }
  .item-box {
    width: 250px;
    min-height: 140px;
    background: #ffffff;
    border-radius: 10px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-content: center;
    cursor: pointer;
    border: 1px solid transparent;
    .item-main {
      width: 100%;
      padding: 15px 20px;
      display: flex;
      flex-direction: column;
      .item-header {
        display: flex;
        flex-direction: row;
        justify-content: flex-start;
        align-items: center;
        .item-name-line {
          width: 1px;
          flex-grow: 1;
          margin-right: 8px;
          box-sizing: border-box;
          display: flex;
          flex-direction: row;
          align-items: center;
          .item-name {
            width: 1px;
            flex-grow: 1;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            box-sizing: border-box;
            color: #333333;
            font-weight: bold;
            font-size: 16px;
          }
        }

        .ac-icon {
          flex-shrink: 0;
          cursor: pointer;
        }

        .el-checkbox__label {
          padding-left: 0;
        }
      }
      .item-remark {
        flex-grow: 1;
        margin-top: 0;
        color: #888888;
        font-size: 12px;
        > span {
          width: 100%;
          display: block;
          height: 1.2em;
          line-height: 1.2;
          overflow: hidden;
          display: -webkit-box;
          -webkit-line-clamp: 1;
          -webkit-box-orient: vertical;
        }
      }
      .item-type {
        color: #999;
        flex-grow: 1;
        margin-top: 8px;
        >div {
          margin-bottom: 3px;
        }
        .text {
          color: #333;
          margin-left: 10px;
        }
      }
      .item-button {
        display: flex;
        flex-direction: row;
        align-items: center;
        .time-box {
          flex-grow: 1;
          color: #999;
        }

        .ac-icon {
          cursor: pointer;
          margin-left: 12px;
        }
      }
    }
  }

  .item-box:hover {
    box-shadow: 0 0 20px 0 rgba(64, 158, 255, 0.25);
  }

  .item-box.active {
    border: 1px solid rgb(64, 158, 255);
    box-shadow: inset 0 0 0 1px rgb(64, 158, 255);
  }
}
.inline-box {
  display: flex;
  flex-direction: row;
}
.dialog-body {
  display: flex;
  flex-direction: row;
  height: calc(100vh - 100px);
  .left {
    width: 150px;
    border-right: 1px solid #fff;
    padding-right: 20px;
    flex-shrink: 0;
    div {
      cursor: pointer;
      margin-bottom: 10px;
      width: 100%;
      height: 40px;
      display: flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
      background-color: white;
      border-radius: 5px;
    }
    div.active {
      color: white;
      background-color: rgb(64, 158, 255);
    }
  }
}
.document-body {
  flex-grow: 1;
  display: grid;
  flex-direction: row;
  grid-template-columns: repeat(auto-fill, 250px);
  grid-gap: 15px;
  justify-content: center;
  align-content: flex-start;
  overflow: auto;

  .file-header {
    margin-bottom: 20px;
    display: flex;
    width: 100%;
    grid-column: 1 / -1;
    text-align: right;
    flex-direction: row;
  }

  .file-item {
    cursor: pointer;
    border: 1px solid transparent;
    width: 250px;
    min-height: 95px;
    background: #ffffff;
    border-radius: 10px;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-content: center;

    .file-box {
      width: 100%;
      padding: 15px 20px;
      display: flex;
      flex-direction: column;

      .file-name {
        width: 100%;
        flex-grow: 1;
        >span {
          line-height: 1.5;
          overflow: hidden;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
        }
      }

      .file-box-footer {
        display: flex;
        flex-direction: row;

        .file-status {
          flex-grow: 1;
          color: #999999;
          display: flex;
          align-items: center;
        }

        .button-list {
          .ac-icon {
            margin-left: 10px;
          }
        }
      }
    }
  }
  .file-item:hover {
    box-shadow: 0 0 20px 0 rgba(64, 158, 255, 0.25);
  }

  .file-item.active {
    border: 1px solid rgb(64, 158, 255);
    box-shadow: inset 0 0 0 1px rgb(64, 158, 255);
  }
}
.hit-test-body {
  flex-grow: 1;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  .chat-line {
    margin: 10px 0;
    flex-grow: 1;
    overflow: auto;
    .chat-item {
      margin-bottom: 20px;
      padding: 20px;
      background-color: white;
      border-radius: 5px;
      .answer {
        margin-top: 8px;
        white-space: pre-wrap;
      }
      .failure {
        color: #ce5050;
      }
    }
  }
  .param-line {
    display: flex;
    align-items: center;
  }
  .query-line {
    margin-top: 10px;
    display: flex;
    align-items: center;
  }
}
</style>